Use case: Clock calibration (interrupt)

The main differences between HAL1 and HAL2 in handling FDCAN clock calibration interrupts are as follows:

  • Activate notifications

    • In HAL1, calibration interrupts are enabled using HAL_FDCAN_ActivateNotification() with interrupts FDCAN_IT_CALIB_STATE_CHANGED and FDCAN_IT_CALIB_WATCHDOG_EVENT.

    • In HAL2, these interrupts are enabled using HAL_FDCAN_CCU_EnableInterrupts(). This is enough since the clock calibration has its own dedicated interrupts line.

  • Interrupt handler

    • In HAL1, all interrupts are handled by HAL_FDCAN_IRQHandler().

    • In HAL2, line 0 and line 1 interrupts are handled by HAL_FDCAN_IRQHandler(), while clock calibration interrupts are handled by HAL_FDCAN_CCU_IRQHandler().

  • Calibration callback

    • In HAL1, the HAL_FDCAN_ClockCalibrationCallback() is triggered with specific flags (FDCAN_IT_CALIB_STATE_CHANGED or FDCAN_IT_CALIB_WATCHDOG_EVENT) to indicate calibration state changes or watchdog events.

    • In HAL2, two callbacks are provided:

      HAL_FDCAN_CCU_CalibrationCallback() to indicate calibration state changes.

      HAL_FDCAN_CCU_CalibrationWatchdogCallback() to indicate that the watchdog expired before calibration completed.

Sequence diagram

  @startuml
  participant App as "User Application"
  participant "<font color=black><b>HAL FDCAN" as FDCAN #19DD3A
  participant "NVIC" as NVIC#AliceBlue

  participant "FDCAN Hardware System" as FDCAN_HW

  == FDCAN  Clock calibration Configuration ==
  App -> FDCAN: HAL_FDCAN_ConfigClockCalibration(&hfdcan, &sCcuConfig)
  FDCAN -> FDCAN_HW: Setup Clock Calibration Unit (CCU)
  FDCAN_HW --> FDCAN: CCU configured
  FDCAN --> App: <color green>HAL_OK

  == Configure Reception Filters and enable interrupt ==
  App -> FDCAN: HAL_FDCAN_ConfigFilter(&hfdcan, &sFilterConfig) [Calibration Filter]
  note right
     Configure at least one filter for both calibration frames to enter the
     BASIC_CALIBRATED and the PRECISION_CALIBRATED
     with IsCalibrationMsg = 1
  endnote
  FDCAN --> App: <color green>HAL_OK

  App -> FDCAN: HAL_FDCAN_ConfigInterruptLines(&hfdcan, FDCAN_IT_RX_BUFFER_NEW_MESSAGE \n , FDCAN_INTERRUPT_LINE0)
  FDCAN --> App: <color green>HAL_OK
  App -> FDCAN: HAL_FDCAN_ActivateNotification(&hfdcan, FDCAN_IT_RX_BUFFER_NEW_MESSAGE \n | FDCAN_IT_CALIB_STATE_CHANGED \n | FDCAN_IT_CALIB_WATCHDOG_EVENT, FDCAN_TX_BUFFER0)
  FDCAN --> App: <color green>HAL_OK
  == FDCAN  Clock calibration Process  ==
  App -> FDCAN: HAL_FDCAN_Start(&hfdcan)
  FDCAN --> App: <color green>HAL_OK
  hNote over FDCAN_HW: The FDCAN in <color red><b>Restricted Operation Mode</b></color>

  hnote over FDCAN_HW
  <font color=red><b>BASIC_CALIBRATION or NOT_CALIBRATED</b>
  end note

  FDCAN_HW <- : FDCAN Rx buffer new calibration message
  note left
  The configured filter <index> accept the calibration message
  end note
  FDCAN_HW --> NVIC: Rx Buffer New Message interrupt \n **FDCAN_IT0_IRQ**
  NVIC -> FDCAN: HAL_FDCAN_IRQHandler()
  FDCAN -> App: HAL_FDCAN_RxBufferNewMessageCallback()
  FDCAN <-- App:
  NVIC <-- FDCAN:
  FDCAN_HW <-- NVIC:
  alt watchdog counter reaches zero before state changed
  FDCAN_HW --> FDCAN_HW: Watchdog counter reaches zero \n before CCU state changed
  FDCAN_HW-->NVIC: CCU watchdog event \n **FDCAN_CCU_IRQ**
  NVIC ->FDCAN: HAL_FDCAN_IRQHandler()

  hnote over FDCAN_HW
  <font color=red><b>NOT_CALIBRATED</b>
  end note

  FDCAN -> App: HAL_FDCAN_ClockCalibrationCallback(&hfdcan, FDCAN_IT_CALIB_WATCHDOG_EVENT)
  hNote over App:<font color=red><b>failed


  else state changed before watchdog counter reaches zero
  FDCAN_HW --> FDCAN_HW: CCU state changed before\nWatchdog counter reaches zero
  FDCAN_HW-->NVIC: CCU state change event \n **FDCAN_CCU_IRQ**
  NVIC ->FDCAN: HAL_FDCAN_IRQHandler()
  FDCAN -> App: HAL_FDCAN_ClockCalibrationCallback(&hfdcan, FDCAN_IT_CALIB_STATE_CHANGED)
  App --> FDCAN:
  FDCAN --> NVIC:


  hnote over FDCAN_HW
  <font color=orange><b>BASIC_CALIBRATION</b>
  end note
  end
  'Precision Calibration Process'

  FDCAN_HW <- : FDCAN **second** Rx buffer new message\n(From quartz node) starts with at least "1010"
  note left
  The configured filter <index> accept the calibration message
  end note

  FDCAN_HW --> NVIC: Rx Buffer New Message interrupt \n **FDCAN_IT0_IRQ**
  NVIC -> FDCAN: HAL_FDCAN_IRQHandler()
  FDCAN -> App: HAL_FDCAN_RxBufferNewMessageCallback()
  FDCAN <-- App:
  NVIC <-- FDCAN:
  FDCAN_HW <-- NVIC:
  alt watchdog counter reaches zero before state changed
  FDCAN_HW --> FDCAN_HW: Watchdog counter reaches zero \n before CCU state changed
  FDCAN_HW-->NVIC: CCU watchdog event \n **FDCAN_CCU_IRQ**
  NVIC ->FDCAN: HAL_FDCAN_IRQHandler()

  hnote over FDCAN_HW
  <font color=red><b>NOT_CALIBRATED</b>
  end note

  FDCAN -> App: HAL_FDCAN_ClockCalibrationCallback(&hfdcan, FDCAN_IT_CALIB_WATCHDOG_EVENT)
  hNote over App:<font color=red><b>failed


  else state changed before watchdog counter reaches zero
  FDCAN_HW --> FDCAN_HW: CCU state changed before\nWatchdog counter reaches zero
  FDCAN_HW-->NVIC: CCU state change event \n **FDCAN_CCU_IRQ**
  NVIC ->FDCAN: HAL_FDCAN_IRQHandler()

  hnote over FDCAN_HW
  <font color=green><b>PRECISION_CALIBRATED</b>
  end note

  FDCAN -> App: HAL_FDCAN_ClockCalibrationCallback(&hfdcan, FDCAN_IT_CALIB_STATE_CHANGED)
  hNote over App:<font color=green><b>Success
           App -> FDCAN: HAL_FDCAN_ExitRestrictedOperationMode
  hNote over FDCAN_HW: The FDCAN in <color green><b>Normal Operation Mode</b></color>
  App <-- FDCAN:<color green>HAL_OK
  end

  Note over App: The FDCAN is calibrated and ready to be used for communication.

  @enduml

Code snippet

HAL1

HAL2

HAL_FDCAN_Start(&hfdcan);

CcuConfig.ClockCalibration     = ENABLE;


CcuConfig.MinOscClkPeriods     = 4;
CcuConfig.CalFieldLength       = FDCAN_CALIB_FIELD_LENGTH_64;
CcuConfig.TimeQuantaPerBitTime = 20;
CcuConfig.WatchdogStartValue   = 40;

HAL_FDCAN_ConfigClockCalibration(&hfdcan, &CcuConfig);

HAL_FDCAN_ConfigInterruptLines(&hfdcan,
                               FDCAN_IT_RX_BUFFER_NEW_MESSAGE
                               FDCAN_INTERRUPT_LINE0);

HAL_FDCAN_ActivateNotification(&hfdcan,
                               FDCAN_IT_RX_BUFFER_NEW_MESSAGE
                               | FDCAN_IT_CALIB_STATE_CHANGED
                               | FDCAN_IT_CALIB_WATCHDOG_EVENT,
                                 FDCAN_TX_BUFFER0);
HAL_FDCAN_Start(&hfdcan);

hal_fdcan_ccu_clock_route_t clock_route = HAL_FDCAN_CCU_CLOCK_ROUTE_CALIBRATION;
HAL_FDCAN_CCU_SetClockRouting(&hfdcan, clock_route);

ccu_config.min_osc_clk_periods          = 4;
ccu_config.calibration_field_length     = HAL_FDCAN_CCU_FIELD_LENGTH_64;
ccu_config.time_quanta_per_bit_time     = 20;
ccu_config.watchdog_start_value         = 40;

HAL_FDCAN_CCU_SetConfigCalibrationUnit(&hfdcan, &ccu_config);

HAL_FDCAN_SetInterruptsToLine(&hfdcan,
               HAL_FDCAN_IT_RX_BUFFER_NEW_MESSAGE
               , HAL_FDCAN_IT_LINE_0);

HAL_FDCAN_EnableInterruptLines(&hfdcan, HAL_FDCAN_IT_LINE_0);

HAL_FDCAN_EnableInterrupts(&hfdcan,
                           HAL_FDCAN_IT_RX_BUFFER_NEW_MESSAGE
                           );
HAL_FDCAN_CCU_EnableInterrupts(&hfdcan,
                               HAL_FDCAN_CCU_IT_CALIBRATION_STATE_CHANGE
                             | HAL_FDCAN_CCU_IT_CALIBRATION_WATCHDOG_EVENT
                               );

Key changes

  1. HAL2 manages clock calibration interrupts through dedicated CCU APIs.

  2. HAL2 introduces a dedicated IRQ handler for CCU interrupts.